package com.hliushi.redis.controller;

import com.google.common.collect.Maps;
import com.hliushi.redis.config.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;

/**
 * @ClassName GeoController
 * @Description TODO
 * @Author hliushi
 * @Date 2021/8/15 10:28
 * @Version V1.0
 **/
@Slf4j
@RequestMapping("/api")
@RestController
public class GeoController {

    @Resource
    private RedisTemplate redisTemplate;


    /**
     * @param
     * @return
     **/
    @GetMapping("/init")
    public void init() {

        /**
         * Point 表示地址空间点值, 经/纬度
         */
        HashMap<String, Point> map = Maps.newHashMap();
        map.put("世界之窗", new Point(113.9807127428, 22.5428248089));
        map.put("南山威尼斯酒店", new Point(113.9832042690, 22.5408496326));
        map.put("福田喜来登酒店", new Point(114.0684865267, 22.5412294122));
        map.put("大梅沙海景酒店", new Point(114.3135524539, 22.5999265998));
        map.put("南山新年酒店", new Point(113.9349465491, 22.5305488659));
        map.put("深圳华强广场酒店", new Point(114.0926367279, 22.5497917634));
        redisTemplate.opsForGeo().add(Constants.HOTEL_KEY, map);
    }


    /**
     * 返回地址名称的 经纬度坐标
     *
     * @param member 地址名称
     * @return 经纬度
     **/
    @GetMapping("/position")
    public Point position(String member) {
        // 获取经纬度坐标
        List<Point> position = redisTemplate.opsForGeo().position(Constants.HOTEL_KEY, member);
        assert position != null;
        return position.get(0);
    }


    /**
     * 返回地址名称的 GeoHash算法生成的base32编码值
     *
     * @param member 地址名称
     * @return
     **/
    @GetMapping("/geohash")
    public String geoHash(String member) {
        List<String> hash = redisTemplate.opsForGeo().hash(Constants.HOTEL_KEY, member);
        assert hash != null;
        return hash.get(0);
    }


    /**
     * 返回给定位置之间的距离
     *
     * @param member1 位置1
     * @param member2 位置2
     * @return 距离
     **/
    @GetMapping("/distance")
    public Distance distance(String member1, String member2) {
        // return redisTemplate.opsForGeo().distance(Constants.HOTEL_KEY, member1, member2, Metrics.MILES);
        return redisTemplate.opsForGeo().distance(Constants.HOTEL_KEY, member1, member2,
                RedisGeoCommands.DistanceUnit.KILOMETERS);
    }

    /**
     * 通过经纬度, 查找附近的
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return GeoResults
     **/
    @GetMapping("/radius-by-xy")
    public GeoResults radiusByXY(String longitude, String latitude) {
        // 这个坐标是腾讯大厦位置
        Circle circle = new Circle(113.9410499639, 22.5461508801, Metrics.KILOMETERS.getMultiplier());

        RedisGeoCommands.GeoRadiusCommandArgs radiusCommandArgs =
                RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(10);

        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults =
                redisTemplate.opsForGeo().radius(Constants.HOTEL_KEY, circle, radiusCommandArgs);

        return geoResults;
    }

    /**
     * 通过地方查找附近
     *
     * @param member 位置名称
     * @return GeoResults
     **/
    @GetMapping("/radius-by-member")
    public GeoResults radiusByMember(String member) {
        RedisGeoCommands.GeoRadiusCommandArgs radiusCommandArgs =
                RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(10);

        // 半径10公里内
        Distance distance = new Distance(10, Metrics.KILOMETERS);
        GeoResults<RedisGeoCommands.GeoLocation<String>> radius = redisTemplate.opsForGeo().radius(Constants.HOTEL_KEY,
                member, distance,
                radiusCommandArgs);

        return radius;
    }


}
